#include "robotaction.h"

RobotAction::RobotAction(Robot* robot, QString name, QObject *parent) :
    QParallelAnimationGroup(parent),
    _name(name),
    _robot(robot),
    _motionTrack(new RobotMotionTrack(robot, this)),
    _facialTrack(new RobotFacialTrack(robot, this)),
    _soundTrack(new SoundTrack(this))
{
    //Claim ownership of null robots (calling setRobot causes a *NULL segfault)
    if (_robot->isNull()) {
        _robot->setParent(this);
    }

    this->addAnimation(_motionTrack);
    //Listen to the motion track key frame signals
    connect(_motionTrack, SIGNAL(keyFrame(int)), this, SLOT(onKeyFrame(int)));
    connect(_motionTrack, SIGNAL(keyFrame(int,int)), this, SLOT(onKeyFrame(int,int)));
    connect(_motionTrack, SIGNAL(keyFrameCreated(int)), this, SLOT(onKeyFrameCreated(int)));
    connect(_motionTrack, SIGNAL(keyFrameDeleted(int)), this, SLOT(onKeyFrameDeleted(int)));
    connect(_motionTrack, SIGNAL(keyFrameDeleted(int,int)), this, SLOT(onKeyFrameDeleted(int,int)));
    connect(_motionTrack, SIGNAL(keyFrameSet(int,int,float)), this, SLOT(onKeyFrameSet(int,int,float)));
    connect(_motionTrack, SIGNAL(keyFrameMoved(int,int)), this, SLOT(onKeyFrameMoved(int,int)));
    connect(_motionTrack, SIGNAL(keyFrameMoved(int,int,int)), this, SLOT(onKeyFrameMoved(int,int,int)));
    connect(_motionTrack, SIGNAL(motionDurationChanged(int,int)), this, SLOT(onMotionDurationChanged(int,int)));

    this->addAnimation(_facialTrack);

    this->addAnimation(_soundTrack);
    //Listen to the soundtrack signals
    connect(_soundTrack, SIGNAL(soundPlayed(int,QString)), this, SLOT(onSoundPlayed(int,QString)));
    connect(_soundTrack, SIGNAL(soundFinished(int,QString)), this, SLOT(onSoundFinished(int,QString)));
    connect(_soundTrack, SIGNAL(soundDurationChanged(int,int)), this, SLOT(onSoundDurationChanged(int,int)));
    connect(_soundTrack, SIGNAL(soundCreated(int,QString)), this, SLOT(onSoundCreated(int,QString)));
    connect(_soundTrack, SIGNAL(soundSet(int,QString)), this, SLOT(onSoundSet(int,QString)));
    connect(_soundTrack, SIGNAL(soundDeleted(int)), this, SLOT(onSoundDeleted(int)));
    connect(_soundTrack, SIGNAL(soundMoved(int,int)), this, SLOT(onSoundMoved(int,int)));
}


RobotAction::~RobotAction(){
}


QString RobotAction::name() const{
    return _name;
}

void RobotAction::setName(QString name){
    _name = name;
}

void RobotAction::setRobot(Robot *robot) {
    //If the old robot is owned by the action, we need to delete it
    if (_robot->parent() == this) {
        _robot->deleteLater();
    }
    _robot = robot;
    //Claim ownership of null robots
    if (_robot->isNull()) {
        _robot->setParent(this);
    }
    _motionTrack->setRobot(_robot);
    skip(0);
}

QList<int> RobotAction::jointIDs() const{
    return _motionTrack->jointIDs();
}

QList<int> RobotAction::activeJointIDs() const{
    return _motionTrack->activeJointIDs();
}

void RobotAction::startBatch(){
    _robot->startBatch();
}

void RobotAction::endBatch(){
    _robot->endBatch();
}

void RobotAction::updateCurrentTime(int currentTime){
    //Call the parent function to update the motion and
    //sound tracks in parallel
    QParallelAnimationGroup::updateCurrentTime(currentTime);

    //Emit the time changed signal once everything is done
    emit timeChanged(currentTime);
}

void RobotAction::updateState(QAbstractAnimation::State newState, QAbstractAnimation::State oldState){
    //Just a minor alteration to the behavior.  If the animation is stopped in the
    //middle of playback, it sets its time to 0 before the next call to play is made.
    //Otherwise, if playback has reached the end of the action, it stays there, and
    //the time is updated to 0 after the next call to play is made.
    if(newState == QAbstractAnimation::Stopped && (currentTime() != duration())){
        updateCurrentTime(0);
    }

    QParallelAnimationGroup::updateState(newState, oldState);
}

void RobotAction::addKeyFrame(MotionKeyFrame frame) {
    foreach (JointValue joint, frame.jointValues) {
        qDebug() << "Adding Keyframe:" << joint.first << joint.second;
        setKeyFrameAt(frame.timestamp, joint.first, joint.second);
    }
}

void RobotAction::setMotionDuration(int msec){
    _motionTrack->setDuration(msec);
}

void RobotAction::setStartValue(int jointID, float theta){
    _motionTrack->setStartValue(jointID, theta);
}

void RobotAction::setEndValue(int jointID, float theta){
    _motionTrack->setEndValue(jointID, theta);
}

MotionKeyFrame RobotAction::insertKeyFrameAt(int msec){
    return _motionTrack->insertKeyFrameAt(msec);
}

float RobotAction::insertKeyFrameAt(int msec, int jointID){
    return _motionTrack->insertKeyFrameAt(msec, jointID);
}

float RobotAction::setKeyFrameAt(int msec, int jointID, float theta){
    return _motionTrack->setKeyFrameAt(msec, jointID, theta);
}

MotionKeyFrame RobotAction::deleteKeyFrameAt(int msec){
    return _motionTrack->deleteKeyFrameAt(msec);
}

float RobotAction::deleteKeyFrameAt(int msec, int jointID){
    return _motionTrack->deleteKeyFrameAt(msec, jointID);
}

void RobotAction::moveKeyFrame(int msec, int newMsec){
    _motionTrack->moveKeyFrame(msec, newMsec);
}

void RobotAction::moveKeyFrame(int msec, int jointID, int newMsec){
    _motionTrack->moveKeyFrame(msec, jointID, newMsec);
}


float RobotAction::keyValueAt(int msec, int jointID) const{
    return _motionTrack->keyValueAt(msec, jointID);
}

int RobotAction::motionDuration() const{
    return _motionTrack->duration();
}

QList<MotionKeyFrame> RobotAction::keyFrames() const{
    return _motionTrack->keyFrames();
}









void RobotAction::setStartExpression(QString filename){
    _facialTrack->setStartExpression(filename);
}

void RobotAction::setEndExpression(QString filename){
    _facialTrack->setEndExpression(filename);
}

void RobotAction::setExpressionAt(int msec, QString filename){
    _facialTrack->setExpressionAt(msec, filename);
}

void RobotAction::moveExpression(int msec, int newMsec){
    _facialTrack->moveExpression(msec, newMsec);
}

void RobotAction::deleteExpression(int msec){
    _facialTrack->deleteExpression(msec);
}

void RobotAction::setFacialTrackDuration(int msec){
    _facialTrack->setDuration(msec);
}

FacialExpressionInfo RobotAction::expressionAt(int msec) const{
    return _facialTrack->expressionAt(msec);
}

QList<FacialExpressionInfo> RobotAction::facialInformation() const{
    return _facialTrack->facialInformation();
}


void RobotAction::setSoundAt(int msec, QString fileName){
    _soundTrack->setSoundAt(msec, fileName);
}

SoundInfo RobotAction::deleteSound(int msec){
    return _soundTrack->deleteSound(msec);
}

void RobotAction::moveSound(int msec, int newMsec){
    _soundTrack->moveSound(msec, newMsec);
}

int RobotAction::trimSound(int msec, int frontTrim, int backTrim){
    return _soundTrack->trimSound(msec, frontTrim, backTrim);
}

void RobotAction::setSoundTrackDuration(int msec){
    _soundTrack->clipTrack(msec);
}

SoundInfo RobotAction::soundAt(int msec) const{
    return _soundTrack->soundAt(msec);
}

QList<SoundInfo> RobotAction::soundInformation() const{
    return _soundTrack->soundInformation();
}


void RobotAction::skip(int msec){
    setCurrentTime(currentTime() + msec);
}

void RobotAction::nextKeyFrame(){
    setCurrentTime(_motionTrack->nextKeyFrame());
}

void RobotAction::prevKeyFrame(){
    setCurrentTime(_motionTrack->prevKeyFrame());
}

//void RobotAction::nextSound(){

//}

//void RobotAction::prevSound(){


//}



/*****************************************************/
/*                      SLOTS                        */
/*****************************************************/
void RobotAction::onKeyFrame(int jointID, int msec){
    emit keyFrame(jointID, msec);
}

void RobotAction::onKeyFrame(int msec){
    emit keyFrame(msec);
}

void RobotAction::onKeyFrameCreated(int msec){
    emit keyFrameCreated(msec);
}

void RobotAction::onKeyFrameSet(int msec, int jointID, float theta){
    emit keyFrameSet(msec, jointID, theta);
}

void RobotAction::onKeyFrameDeleted(int msec){
    emit keyFrameDeleted(msec);
}

void RobotAction::onKeyFrameDeleted(int msec, int jointID){
    emit keyFrameDeleted(msec, jointID);
}

void RobotAction::onKeyFrameMoved(int msec, int newMsec){
    emit keyFrameMoved(msec, newMsec);
}

void RobotAction::onKeyFrameMoved(int msec, int jointID, int newMsec){
    emit keyFrameMoved(msec, jointID, newMsec);
}

void RobotAction::onMotionDurationChanged(int newMsec, int oldMsec){
    emit motionDurationChanged(newMsec, oldMsec);
}

void RobotAction::onSoundPlayed(int msec, QString name){
    emit soundPlayed(msec, name);
}

void RobotAction::onSoundFinished(int msec, QString name){
    emit soundFinished(msec, name);
}

void RobotAction::onSoundDurationChanged(int msec, int newDuration){
    emit soundDurationChanged(msec, newDuration);
}

void RobotAction::onSoundCreated(int msec, QString name){
    emit soundCreated(msec, name);
}

void RobotAction::onSoundSet(int msec, QString name){
    emit soundSet(msec, name);
}

void RobotAction::onSoundDeleted(int msec){
    emit soundDeleted(msec);
}

void RobotAction::onSoundMoved(int msec, int newMsec){
    emit soundMoved(msec, newMsec);
}
